home *** CD-ROM | disk | FTP | other *** search
- /*
- * tkGrid.c --
- *
- * Grid based geometry manager.
- *
- * Copyright (c) 1996 by Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- *
- * SCCS: @(#) tkGrid.c 1.21 96/02/21 10:50:58
- */
-
- #include "tkInt.h"
-
- /*
- * LayoutInfo structure. We shouldn't be using hard-wired limits!
- */
-
- #define MAXGRIDSIZE 128
- #ifndef MAXINT
- # define MAXINT 0x7fff
- #endif
- #define MINWEIGHT 0.0001 /* weight totals < this are considered to be zero */
-
- /*
- * Special characters to support relative layouts
- */
-
- #define REL_SKIP 'x' /* skip this column */
- #define REL_HORIZ '-' /* extend previous widget horizontally */
- #define REL_VERT '^' /* extend previous widget verticallly */
-
- /*
- * structure to hold collected constraints temporarily:
- * needs to use a "Constrain" thingy
- */
-
- typedef struct {
- int width, height; /* number of cells horizontally, vertically */
- int lastRow; /* last cell with a window in it */
- int minWidth[MAXGRIDSIZE]; /* largest minWidth in each column */
- int minHeight[MAXGRIDSIZE]; /* largest minHeight in each row */
- double weightX[MAXGRIDSIZE]; /* largest weight in each column */
- double weightY[MAXGRIDSIZE]; /* largest weight in each row */
- } LayoutInfo;
-
- /* structure for holding row and column constraints */
-
- typedef struct {
- int used; /* maximum element used */
- int max; /* maximum element allocated */
- int *minsize; /* array of minimum column/row sizes */
- double *weight; /* array of column/row weights */
- } Constrain;
-
- /* For each window that the gridbag cares about (either because
- * the window is managed by the gridbag or because the window
- * has slaves that are managed by the gridbag), there is a
- * structure of the following type:
- */
-
- typedef struct GridBag {
- Tk_Window tkwin; /* Tk token for window. NULL means that
- * the window has been deleted, but the
- * packet hasn't had a chance to clean up
- * yet because the structure is still in
- * use. */
- struct GridBag *masterPtr; /* Master window within which this window
- * is managed (NULL means this window
- * isn't managed by the gridbag). */
- struct GridBag *nextPtr; /* Next window managed within same
- * parent. List is priority-ordered:
- * first on list gets layed out first. */
- struct GridBag *slavePtr; /* First in list of slaves managed
- * inside this window (NULL means
- * no gridbag slaves). */
-
- int gridColumn, gridRow;
- int gridWidth, gridHeight;
-
- int tempX, tempY;
- int tempWidth, tempHeight;
-
- double weightX, weightY;
- int minWidth, minHeight;
-
- int padX, padY; /* Total additional pixels to leave around the
- * window (half of this space is left on each
- * side). This is space *outside* the window:
- * we'll allocate extra space in frame but
- * won't enlarge window). */
- int iPadX, iPadY; /* Total extra pixels to allocate inside the
- * window (half this amount will appear on
- * each side). */
- int startx, starty; /* starting location of layout */
-
- int doubleBw; /* Twice the window's last known border
- * width. If this changes, the window
- * must be re-arranged within its parent. */
- int *abortPtr; /* If non-NULL, it means that there is a nested
- * call to ArrangeGrid already working on
- * this window. *abortPtr may be set to 1 to
- * abort that nested call. This happens, for
- * example, if tkwin or any of its slaves
- * is deleted. */
- int flags; /* Miscellaneous flags; see below
- * for definitions. */
-
- Constrain row, column; /* column and row constraints */
-
- int valid;
- LayoutInfo *layoutCache;
- } GridBag;
-
- /*
- * Flag values for GridBag structures:
- *
- * REQUESTED_RELAYOUT: 1 means a Tk_DoWhenIdle request
- * has already been made to re-arrange
- * all the slaves of this window.
- * STICK_NORTH 1 means this window sticks to the edgth of its
- * STICK_EAST cavity
- * STICK_SOUTH
- * STICK_WEST
- *
- * DONT_PROPAGATE: 1 means don't set this window's requested
- * size. 0 means if this window is a master
- * then Tk will set its requested size to fit
- * the needs of its slaves.
- */
-
- #define STICK_NORTH 1
- #define STICK_EAST 2
- #define STICK_SOUTH 4
- #define STICK_WEST 8
- #define STICK_ALL (STICK_NORTH|STICK_EAST|STICK_SOUTH|STICK_WEST)
-
- #define REQUESTED_RELAYOUT 16
- #define DONT_PROPAGATE 32
-
- /*
- * Hash table used to map from Tk_Window tokens to corresponding
- * GridBag structures:
- */
-
- static Tcl_HashTable gridBagHashTable;
-
- /*
- * Have statics in this module been initialized?
- */
-
- static initialized = 0;
-
- /*
- * Prototypes for procedures used only in this file:
- */
-
- static void ArrangeGrid _ANSI_ARGS_((ClientData clientData));
- static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
- Tk_Window tkwin, int argc, char *argv[]));
- static void DestroyGridBag _ANSI_ARGS_((char *memPtr));
- static void GetCachedLayoutInfo _ANSI_ARGS_((GridBag *masterPtr));
- static GridBag * GetGridBag _ANSI_ARGS_((Tk_Window tkwin));
- static void GetLayoutInfo _ANSI_ARGS_((GridBag *masterPtr,
- LayoutInfo *r));
- static void GetMinSize _ANSI_ARGS_((GridBag *masterPtr,
- LayoutInfo *info, int *minw, int *minh));
- static void GridBagStructureProc _ANSI_ARGS_((
- ClientData clientData, XEvent *eventPtr));
- static void GridLostSlaveProc _ANSI_ARGS_((ClientData clientData,
- Tk_Window tkwin));
- static void GridReqProc _ANSI_ARGS_((ClientData clientData,
- Tk_Window tkwin));
- static void GridBagStructureProc _ANSI_ARGS_((
- ClientData clientData, XEvent *eventPtr));
- static void StickyToString _ANSI_ARGS_((int flags, char *result));
- static int StringToSticky _ANSI_ARGS_((char *string));
- static void Unlink _ANSI_ARGS_((GridBag *gridPtr));
-
- static Tk_GeomMgr gridMgrType = {
- "grid", /* name */
- GridReqProc, /* requestProc */
- GridLostSlaveProc, /* lostSlaveProc */
- };
-
- /*
- *--------------------------------------------------------------
- *
- * Tk_GridCmd --
- *
- * This procedure is invoked to process the "grid" Tcl command.
- * See the user documentation for details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
- int
- Tk_GridCmd(clientData, interp, argc, argv)
- ClientData clientData; /* Main window associated with
- * interpreter. */
- Tcl_Interp *interp; /* Current interpreter. */
- int argc; /* Number of arguments. */
- char **argv; /* Argument strings. */
- {
- Tk_Window tkwin = (Tk_Window) clientData;
- size_t length;
- char c;
-
- if ((argc >= 2) && (argv[1][0] == '.')) {
- return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
- }
- if (argc < 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " option arg ?arg ...?\"", (char *) NULL);
- return TCL_ERROR;
- }
- c = argv[1][0];
- length = strlen(argv[1]);
-
- if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
- Tk_Window master;
- GridBag *masterPtr;
- int row, column;
- int i, x, y;
- int prevX, prevY;
- int width, height;
- double weight;
- int diff;
-
- if (argc != 5) {
- Tcl_AppendResult(interp, "Wrong number of arguments: ",
- "must be \"",argv[0],
- " bbox <master> <column> <row>\"", (char *) NULL);
- return TCL_ERROR;
- }
-
- master = Tk_NameToWindow(interp, argv[2], tkwin);
- if (master == NULL) {
- return TCL_ERROR;
- }
- if (Tcl_GetInt(interp, argv[3], &column) != TCL_OK) {
- return TCL_ERROR;
- }
- if (Tcl_GetInt(interp, argv[4], &row) != TCL_OK) {
- return TCL_ERROR;
- }
- masterPtr = GetGridBag(master);
-
- /* make sure the grid is up to snuff */
-
- while ((masterPtr->flags & REQUESTED_RELAYOUT)) {
- Tk_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr);
- ArrangeGrid((ClientData) masterPtr);
- }
- GetCachedLayoutInfo(masterPtr);
-
- if (row < 0 || column < 0) {
- *interp->result = '\0';
- return TCL_OK;
- }
- if (column >= masterPtr->layoutCache->width ||
- row >= masterPtr->layoutCache->height) {
- *interp->result = '\0';
- return TCL_OK;
- }
- x = masterPtr->startx;
- y = masterPtr->starty;
- GetMinSize(masterPtr, masterPtr->layoutCache, &width, &height);
-
- diff = Tk_Width(masterPtr->tkwin) - (width + masterPtr->iPadX);
- for (weight=0.0, i=0; i<masterPtr->layoutCache->width; i++)
- weight += masterPtr->layoutCache->weightX[i];
-
- prevX = 0; /* Needed to prevent gcc warning. */
- for (i=0; i<=column; i++) {
- int dx = 0;
- if (weight > MINWEIGHT) {
- dx = (int)((((double)diff) * masterPtr->layoutCache->weightX[i])
- / weight);
- }
- prevX = x;
- x += masterPtr->layoutCache->minWidth[i] + dx;
- }
- diff = Tk_Height(masterPtr->tkwin) - (height + masterPtr->iPadY);
- for (weight=0.0, i=0; i<masterPtr->layoutCache->width; i++) {
- weight += masterPtr->layoutCache->weightY[i];
- }
- prevY = 0; /* Needed to prevent gcc warning. */
- for (i=0; i<=row; i++) {
- int dy = 0;
- if (weight > MINWEIGHT) {
- dy = (int)((((double)diff) * masterPtr->layoutCache->weightY[i])
- / weight);
- }
- prevY = y;
- y += masterPtr->layoutCache->minHeight[i] + dy;
- }
- sprintf(interp->result,"%d %d %d %d",prevX,prevY,x - prevX,y - prevY);
- } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
- if (argv[2][0] != '.') {
- Tcl_AppendResult(interp, "bad argument \"", argv[2],
- "\": must be name of window", (char *) NULL);
- return TCL_ERROR;
- }
- return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
- } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
- Tk_Window slave;
- GridBag *slavePtr;
- int i;
-
- for (i = 2; i < argc; i++) {
- slave = Tk_NameToWindow(interp, argv[i], tkwin);
- if (slave == NULL) {
- return TCL_ERROR;
- }
- slavePtr = GetGridBag(slave);
- if (slavePtr->masterPtr != NULL) {
- Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
- (ClientData) NULL);
- Unlink(slavePtr);
- Tk_UnmapWindow(slavePtr->tkwin);
- }
- }
- } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
- register GridBag *slavePtr;
- Tk_Window slave;
- char buffer[64];
-
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " info window\"", (char *) NULL);
- return TCL_ERROR;
- }
- slave = Tk_NameToWindow(interp, argv[2], tkwin);
- if (slave == NULL) {
- return TCL_ERROR;
- }
- slavePtr = GetGridBag(slave);
- if (slavePtr->masterPtr == NULL) {
- interp->result[0] = '\0';
- return TCL_OK;
- }
-
- Tcl_AppendElement(interp, "-in");
- Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
- sprintf(buffer, " -column %d -row %d -columnspan %d -rowspan %d",
- slavePtr->gridColumn, slavePtr->gridRow,
- slavePtr->gridWidth, slavePtr->gridHeight);
- Tcl_AppendResult(interp, buffer, (char *) NULL);
- sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
- slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
- slavePtr->padY/2);
- Tcl_AppendResult(interp, buffer, (char *) NULL);
- StickyToString(slavePtr->flags,buffer);
- Tcl_AppendResult(interp, " -sticky ", buffer, (char *) NULL);
- /*
- sprintf(buffer, " -weightx %.2f -weighty %.2f",
- slavePtr->weightX, slavePtr->weightY);
- Tcl_AppendResult(interp, buffer, (char *) NULL);
- */
- } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
- Tk_Window master;
- GridBag *masterPtr;
- int propagate;
-
- if (argc > 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " propagate window ?boolean?\"",
- (char *) NULL);
- return TCL_ERROR;
- }
- master = Tk_NameToWindow(interp, argv[2], tkwin);
- if (master == NULL) {
- return TCL_ERROR;
- }
- masterPtr = GetGridBag(master);
- if (argc == 3) {
- #ifdef STk_CODE
- interp->result = (masterPtr->flags & DONT_PROPAGATE) ? "#f" : "#t";
- #else
- interp->result = (masterPtr->flags & DONT_PROPAGATE) ? "0" : "1";
- #endif
- return TCL_OK;
- }
- if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
- return TCL_ERROR;
- }
- if (propagate) {
- masterPtr->flags &= ~DONT_PROPAGATE;
-
- /*
- * Re-arrange the master to allow new geometry information to
- * propagate upwards to the master\'s master.
- */
-
- if (masterPtr->abortPtr != NULL) {
- *masterPtr->abortPtr = 1;
- }
- masterPtr->valid = 0;
- if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
- masterPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
- }
- } else {
- masterPtr->flags |= DONT_PROPAGATE;
- }
- } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)) {
- Tk_Window master;
- GridBag *masterPtr;
-
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " size window\"", (char *) NULL);
- return TCL_ERROR;
- }
- master = Tk_NameToWindow(interp, argv[2], tkwin);
- if (master == NULL)
- return TCL_ERROR;
- masterPtr = GetGridBag(master);
- GetCachedLayoutInfo(masterPtr);
-
- sprintf(interp->result, "%d %d", masterPtr->layoutCache->width,
- masterPtr->layoutCache->height);
- } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) {
- Tk_Window master;
- GridBag *masterPtr, *slavePtr;
- int i, value;
- int row = -1, column = -1;
-
- if (argc < 3 || argc%2 ==0) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " slaves window ?-option value...?\"",
- (char *) NULL);
- return TCL_ERROR;
- }
-
- for (i=3; i<argc; i+=2) {
- if (*argv[i] != '-' || (length = strlen(argv[i])) < 2) {
- Tcl_AppendResult(interp, "Invalid args: should be \"",
- argv[0], " slaves window ?-option value...?\"",
- (char *) NULL);
- return TCL_ERROR;
- }
- if (Tcl_GetInt(interp, argv[i+1], &value) != TCL_OK) {
- return TCL_ERROR;
- }
- if (value < 0) {
- Tcl_AppendResult(interp, argv[i],
- " is an invalid value: should NOT be < 0",
- (char *) NULL);
- return TCL_ERROR;
- }
- if (strncmp(argv[i], "-column", length) == 0) {
- column = value;
- } else if (strncmp(argv[i], "-row", length) == 0) {
- row = value;
- } else {
- Tcl_AppendResult(interp, argv[i],
- " is an invalid option: should be \"",
- "-row, -column\"",
- (char *) NULL);
- return TCL_ERROR;
- }
- }
- master = Tk_NameToWindow(interp, argv[2], tkwin);
- if (master == NULL) {
- return TCL_ERROR;
- }
- masterPtr = GetGridBag(master);
- #ifdef STk_CODE
- Tcl_AppendResult(interp, "(", NULL);
- #endif
- for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
- slavePtr = slavePtr->nextPtr) {
- if (column>=0 && (slavePtr->gridColumn > column
- || slavePtr->gridColumn+slavePtr->gridWidth-1 < column)) {
- continue;
- }
- if (row>=0 && (slavePtr->gridRow > row ||
- slavePtr->gridRow+slavePtr->gridHeight-1 < row)) {
- continue;
- }
- Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
- }
- #ifdef STk_CODE
- Tcl_AppendResult(interp, ")", NULL);
- #endif
-
- /*
- * grid columnconfigure <master> <index> -option
- * grid columnconfigure <master> <index> -option value -option value
- * grid rowconfigure <master> <index> -option
- * grid rowconfigure <master> <index> -option value -option value
- */
-
- } else if(((c=='c') && (strncmp(argv[1], "columnconfigure", length) == 0)) ||
- ((c=='r') && (strncmp(argv[1], "rowconfigure", length) == 0))) {
- Tk_Window master;
- GridBag *masterPtr;
- Constrain *con;
- int index, i, size;
- double weight;
-
- if (argc != 5 && (argc < 5 || argc%2 == 1)) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " ", argv[1], " master index ?-option value...?\"",
- (char *)NULL);
- return TCL_ERROR;
- }
-
- master = Tk_NameToWindow(interp, argv[2], tkwin);
- if (master == NULL) {
- return TCL_ERROR;
- }
- masterPtr = GetGridBag(master);
- con = (c=='c') ? &(masterPtr->column) : &(masterPtr->row);
-
- if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) {
- return TCL_ERROR;
- }
- if (index < 0 || index >= MAXGRIDSIZE) {
- Tcl_AppendResult(interp, argv[3], " is out of range",
- (char *)NULL);
- return TCL_ERROR;
- }
-
- /*
- * make sure the row/column constraint array is allocated. This
- * Should be changed to avoid hard-wired limits. We'll wimp out
- * for now.
- */
-
- if (con->max == 0) {
- unsigned int size;
- con->max = MAXGRIDSIZE;
- con->used = 0;
-
- size = MAXGRIDSIZE * sizeof(con->minsize[0]);
- con->minsize = (int *) ckalloc(size);
- memset(con->minsize, 0, size);
-
- size = MAXGRIDSIZE * sizeof(con->weight[0]);
- con->weight = (double *) ckalloc(size);
- memset(con->weight, 0, size);
- }
-
- for (i=4; i<argc; i+=2) {
- if (*argv[i] != '-' || (length = strlen(argv[i])) < 2) {
- Tcl_AppendResult(interp, "Invalid arg: \"",
- argv[0], "\" expecting -minsize or -weight",
- (char *) NULL);
- return TCL_ERROR;
- }
- if (strncmp(argv[i], "-minsize", length) == 0) {
- if (argc == 5) {
- size = con->used <= index ? 0 : con->minsize[index];
- sprintf(interp->result, "%d", size);
- } else if (Tk_GetPixels(interp, master, argv[i+1], &size)
- != TCL_OK) {
- return TCL_ERROR;
- } else {
- con->minsize[index] = size;
- if (size > 0 && index >= con->used)
- con->used = index+1;
- else if (size == 0 && index+1 == con->used) {
- while (index >= 0 && (con->minsize[index]==0) &&
- (con->weight[index] == 0.0)) {
- index--;
- }
- con->used = index + 1;
- }
- }
- } else if (strncmp(argv[i], "-weight", length) == 0) {
- if (argc == 5) {
- weight = con->used <= index ? 0 : con->weight[index];
- sprintf(interp->result, "%.2f", weight);
- } else if (Tcl_GetDouble(interp, argv[i+1], &weight) != TCL_OK) {
- return TCL_ERROR;
- } else {
- con->weight[index] = weight;
- if (weight > MINWEIGHT && index >= con->used)
- con->used = index+1;
- else if (weight == 0.0 && index+1 == con->used) {
- while (index >= 0 && (con->minsize[index]==0) &&
- (con->weight[index] == 0.0)) {
- index--;
- }
- con->used = index + 1;
- }
- }
- } else {
- Tcl_AppendResult(interp, argv[i],
- " is an invalid option: should be \"",
- "-minsize, -weight\"",
- (char *) NULL);
- return TCL_ERROR;
- }
- }
-
- /* if we changed a property, re-arrange the table */
-
- if (argc != 5) {
- if (masterPtr->abortPtr != NULL) {
- *masterPtr->abortPtr = 1;
- }
- masterPtr->valid = 0;
- if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
- masterPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
- }
- }
- } else if((c == 'l') && (strncmp(argv[1], "location", length) == 0)) {
- Tk_Window master;
- GridBag *masterPtr;
- int x, y, i, j, w, h;
- int width, height;
- double weight;
- int diff;
-
- if (argc != 5) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " location master x y\"", (char *)NULL);
- return TCL_ERROR;
- }
-
- master = Tk_NameToWindow(interp, argv[2], tkwin);
- if (master == NULL) {
- return TCL_ERROR;
- }
- masterPtr = GetGridBag(master);
-
- if (Tk_GetPixels(interp, master, argv[3], &x) != TCL_OK) {
- return TCL_ERROR;
- }
- if (Tk_GetPixels(interp, master, argv[4], &y) != TCL_OK) {
- return TCL_ERROR;
- }
-
- /* make sure the grid is up to snuff */
-
- while ((masterPtr->flags & REQUESTED_RELAYOUT)) {
- Tk_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr);
- ArrangeGrid((ClientData) masterPtr);
- }
- GetCachedLayoutInfo(masterPtr);
- GetMinSize(masterPtr, masterPtr->layoutCache, &width, &height);
-
- diff = Tk_Width(masterPtr->tkwin) - (width + masterPtr->iPadX);
- for (weight=0.0, i=0; i<masterPtr->layoutCache->width; i++) {
- weight += masterPtr->layoutCache->weightX[i];
- }
- w = masterPtr->startx;
- if (w > x) {
- i = -1;
- } else {
- for (i=0; i<masterPtr->layoutCache->width; i++) {
- int dx = 0;
- if (weight > MINWEIGHT) {
- dx = (int)((((double)diff) * masterPtr->layoutCache->weightX[i])
- / weight);
- }
- w += masterPtr->layoutCache->minWidth[i] + dx;
- if (w > x) {
- break;
- }
- }
- }
-
- diff = Tk_Height(masterPtr->tkwin) - (height + masterPtr->iPadY);
- for (weight=0.0, j = 0; j < masterPtr->layoutCache->height; j++)
- weight += masterPtr->layoutCache->weightY[j];
- h = masterPtr->starty;
- if (h > y) {
- j = -1;
- } else {
- for (j=0; j<masterPtr->layoutCache->height; j++) {
- int dy = 0;
- if (weight > MINWEIGHT) {
- dy = (int)((((double)diff) * masterPtr->layoutCache->weightY[j])
- / weight);
- }
- h += masterPtr->layoutCache->minHeight[j] + dy;
- if (h > y) {
- break;
- }
- }
- }
- sprintf(interp->result, "%d %d", i, j);
- } else {
- Tcl_AppendResult(interp, "bad option \"", argv[1],
- "\": must be bbox, columnconfigure, configure, forget, info, ",
- "location, propagate, rowconfigure, size, or slaves",
- (char *) NULL);
- return TCL_ERROR;
- }
- return TCL_OK;
- }
-
- /*
- *--------------------------------------------------------------
- *
- * GridReqProc --
- *
- * This procedure is invoked by Tk_GeometryRequest for
- * windows managed by the gridbag.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Arranges for tkwin, and all its managed siblings, to
- * be re-arranged at the next idle point.
- *
- *--------------------------------------------------------------
- */
-
- /* ARGSUSED */
- static void
- GridReqProc(clientData, tkwin)
- ClientData clientData; /* GridBag's information about
- * window that got new preferred
- * geometry. */
- Tk_Window tkwin; /* Other Tk-related information
- * about the window. */
- {
- register GridBag *gridPtr = (GridBag *) clientData;
-
- gridPtr = gridPtr->masterPtr;
- gridPtr->valid = 0;
- if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
- gridPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
- }
- }
-
-
- /*
- *--------------------------------------------------------------
- *
- * GridLostSlaveProc --
- *
- * This procedure is invoked by Tk whenever some other geometry
- * claims control over a slave that used to be managed by us.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Forgets all grid-related information about the slave.
- *
- *--------------------------------------------------------------
- */
-
- /* ARGSUSED */
- static void
- GridLostSlaveProc(clientData, tkwin)
- ClientData clientData; /* GridBag structure for slave window that
- * was stolen away. */
- Tk_Window tkwin; /* Tk's handle for the slave window. */
- {
- register GridBag *slavePtr = (GridBag *) clientData;
-
- if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
- Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
- }
- Unlink(slavePtr);
- Tk_UnmapWindow(slavePtr->tkwin);
- }
-
- /*
- * Fill in an instance of the above structure for the current set
- * of managed children. This requires two passes through the
- * set of children, first to figure out what cells they occupy
- * and how many rows and columns there are, and then to distribute
- * the weights and min sizes amoung the rows/columns.
- *
- * This also caches the minsizes for all the children when they are
- * first encountered.
- */
-
- static void
- GetLayoutInfo(masterPtr, r)
- GridBag *masterPtr;
- LayoutInfo *r;
- {
- register GridBag *slavePtr;
- int i, k, px, py, pixels_diff, nextSize;
- double weight_diff, weight;
- register int curX, curY, curWidth, curHeight, curRow, curCol;
- int xMax[MAXGRIDSIZE];
- int yMax[MAXGRIDSIZE];
-
- /*
- * Pass #1
- *
- * Figure out the dimensions of the layout grid.
- */
-
- r->width = r->height = 0;
- curRow = curCol = -1;
- memset(xMax, 0, sizeof(int) * MAXGRIDSIZE);
- memset(yMax, 0, sizeof(int) * MAXGRIDSIZE);
-
- for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
- slavePtr = slavePtr->nextPtr) {
-
- curX = slavePtr->gridColumn;
- curY = slavePtr->gridRow;
- curWidth = slavePtr->gridWidth;
- curHeight = slavePtr->gridHeight;
-
- /* Adjust the grid width and height */
- for (px = curX + curWidth; r->width < px; r->width++) {
- /* Null body. */
- }
- for (py = curY + curHeight; r->height < py; r->height++) {
- /* Null body. */
- }
-
- /* Adjust the xMax and yMax arrays */
- for (i = curX; i < (curX + curWidth); i++) {
- yMax[i] = py;
- }
- for (i = curY; i < (curY + curHeight); i++) {
- xMax[i] = px;
- }
-
- /* Cache the current slave's size. */
- slavePtr->minWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw;
- slavePtr->minHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw;
- }
-
- /*
- * Apply minimum row/column dimensions
- */
- if (r->width < masterPtr->column.used) {
- r->width = masterPtr->column.used;
- }
- r->lastRow = r->height;
- if (r->height < masterPtr->row.used) {
- r->height = masterPtr->row.used;
- }
-
- /*
- * Pass #2
- */
-
- curRow = curCol = -1;
- memset(xMax, 0, sizeof(int) * MAXGRIDSIZE);
- memset(yMax, 0, sizeof(int) * MAXGRIDSIZE);
-
- for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
- slavePtr = slavePtr->nextPtr) {
- curX = slavePtr->gridColumn;
- curY = slavePtr->gridRow;
- curWidth = slavePtr->gridWidth;
- curHeight = slavePtr->gridHeight;
-
- px = curX + curWidth;
- py = curY + curHeight;
-
- for (i = curX; i < (curX + curWidth); i++) {
- yMax[i] = py;
- }
- for (i = curY; i < (curY + curHeight); i++) {
- xMax[i] = px;
- }
-
- /* Assign the new values to the gridbag slave */
- slavePtr->tempX = curX;
- slavePtr->tempY = curY;
- slavePtr->tempWidth = curWidth;
- slavePtr->tempHeight = curHeight;
- }
-
- /*
- * Pass #3
- *
- * Distribute the minimun widths and weights:
- */
-
- /* Initialize arrays to zero */
- memset(r->minWidth, 0, r->width * sizeof(int));
- memset(r->minHeight, 0, r->height * sizeof(int));
- memset(r->weightX, 0, r->width * sizeof(double));
- memset(r->weightY, 0, r->height * sizeof(double));
- nextSize = MAXINT;
-
- for (i = 1; i != MAXINT; i = nextSize, nextSize = MAXINT) {
- for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
- slavePtr = slavePtr->nextPtr) {
-
- if (slavePtr->tempWidth == i) {
- px = slavePtr->tempX + slavePtr->tempWidth; /* right column */
-
- /*
- * Figure out if we should use this slave\'s weight. If the weight
- * is less than the total weight spanned by the width of the cell,
- * then discard the weight. Otherwise split it the difference
- * according to the existing weights.
- */
-
- weight_diff = slavePtr->weightX;
- for (k = slavePtr->tempX; k < px; k++)
- weight_diff -= r->weightX[k];
- if (weight_diff > 0.0) {
- weight = 0.0;
- for (k = slavePtr->tempX; k < px; k++)
- weight += r->weightX[k];
- for (k = slavePtr->tempX; weight > MINWEIGHT; k++) {
- double wt = r->weightX[k];
- double dx = (wt * weight_diff) / weight;
- r->weightX[k] += dx;
- weight_diff -= dx;
- weight -= wt;
- }
- /* Assign the remainder to the rightmost cell */
- r->weightX[px-1] += weight_diff;
- }
-
- /*
- * Calculate the minWidth array values.
- * First, figure out how wide the current slave needs to be.
- * Then, see if it will fit within the current minWidth values.
- * If it won\'t fit, add the difference according to the weightX array.
- */
-
- pixels_diff = slavePtr->minWidth + slavePtr->padX + slavePtr->iPadX;
- for (k = slavePtr->tempX; k < px; k++)
- pixels_diff -= r->minWidth[k];
- if (pixels_diff > 0) {
- weight = 0.0;
- for (k = slavePtr->tempX; k < px; k++)
- weight += r->weightX[k];
- for (k = slavePtr->tempX; weight > MINWEIGHT; k++) {
- double wt = r->weightX[k];
- int dx = (int)((wt * ((double)pixels_diff)) / weight);
- r->minWidth[k] += dx;
- pixels_diff -= dx;
- weight -= wt;
- }
- /* Any leftovers go into the rightmost cell */
- r->minWidth[px-1] += pixels_diff;
- }
- }
- else if (slavePtr->tempWidth > i && slavePtr->tempWidth < nextSize)
- nextSize = slavePtr->tempWidth;
-
-
- if (slavePtr->tempHeight == i) {
- py = slavePtr->tempY + slavePtr->tempHeight; /* bottom row */
-
- /*
- * Figure out if we should use this slave\'s weight. If the weight
- * is less than the total weight spanned by the height of the cell,
- * then discard the weight. Otherwise split it the difference
- * according to the existing weights.
- */
-
- weight_diff = slavePtr->weightY;
- for (k = slavePtr->tempY; k < py; k++)
- weight_diff -= r->weightY[k];
- if (weight_diff > 0.0) {
- weight = 0.0;
- for (k = slavePtr->tempY; k < py; k++)
- weight += r->weightY[k];
- for (k = slavePtr->tempY; weight > MINWEIGHT; k++) {
- double wt = r->weightY[k];
- double dy = (wt * weight_diff) / weight;
- r->weightY[k] += dy;
- weight_diff -= dy;
- weight -= wt;
- }
- /* Assign the remainder to the bottom cell */
- r->weightY[py-1] += weight_diff;
- }
-
- /*
- * Calculate the minHeight array values.
- * First, figure out how tall the current slave needs to be.
- * Then, see if it will fit within the current minHeight values.
- * If it won\'t fit, add the difference according to the weightY array.
- */
-
- pixels_diff = slavePtr->minHeight + slavePtr->padY + slavePtr->iPadY;
- for (k = slavePtr->tempY; k < py; k++)
- pixels_diff -= r->minHeight[k];
- if (pixels_diff > 0) {
- weight = 0.0;
- for (k = slavePtr->tempY; k < py; k++)
- weight += r->weightY[k];
- for (k = slavePtr->tempY; weight > MINWEIGHT; k++) {
- double wt = r->weightY[k];
- int dy = (int)((wt * ((double)pixels_diff)) / weight);
- r->minHeight[k] += dy;
- pixels_diff -= dy;
- weight -= wt;
- }
- /* Any leftovers go into the bottom cell */
- r->minHeight[py-1] += pixels_diff;
- }
- }
- else if (slavePtr->tempHeight > i && slavePtr->tempHeight < nextSize)
- nextSize = slavePtr->tempHeight;
- }
- }
-
- /*
- * Apply minimum row/column dimensions
- */
- for (i=0; i<masterPtr->column.used; i++) {
- if (r->minWidth[i] < masterPtr->column.minsize[i])
- r->minWidth[i] = masterPtr->column.minsize[i];
- if (r->weightX[i] < masterPtr->column.weight[i])
- r->weightX[i] = masterPtr->column.weight[i];
- }
- for (i=0; i<masterPtr->row.used; i++) {
- if (r->minHeight[i] < masterPtr->row.minsize[i])
- r->minHeight[i] = masterPtr->row.minsize[i];
- if (r->weightY[i] < masterPtr->row.weight[i])
- r->weightY[i] = masterPtr->row.weight[i];
- }
- }
-
- /*
- * Cache the layout info after it is calculated.
- */
- static void
- GetCachedLayoutInfo(masterPtr)
- GridBag *masterPtr;
- {
- if (masterPtr->valid == 0) {
- if (!masterPtr->layoutCache)
- masterPtr->layoutCache = (LayoutInfo *)ckalloc(sizeof(LayoutInfo));
-
- GetLayoutInfo(masterPtr, masterPtr->layoutCache);
- masterPtr->valid = 1;
- }
- }
-
- /*
- * Adjusts the x, y, width, and height fields to the correct
- * values depending on the constraint geometry and pads.
- */
-
- static void
- AdjustForGravity(gridPtr, x, y, width, height)
- GridBag *gridPtr;
- int *x;
- int *y;
- int *width;
- int *height;
- {
- int diffx=0, diffy=0;
- int sticky = gridPtr->flags&STICK_ALL;
-
- *x += gridPtr->padX/2;
- *width -= gridPtr->padX;
- *y += gridPtr->padY/2;
- *height -= gridPtr->padY;
-
- if (*width > (gridPtr->minWidth + gridPtr->iPadX)) {
- diffx = *width - (gridPtr->minWidth + gridPtr->iPadX);
- *width = gridPtr->minWidth + gridPtr->iPadX;
- }
-
- if (*height > (gridPtr->minHeight + gridPtr->iPadY)) {
- diffy = *height - (gridPtr->minHeight + gridPtr->iPadY);
- *height = gridPtr->minHeight + gridPtr->iPadY;
- }
-
- if (sticky&STICK_EAST && sticky&STICK_WEST)
- *width += diffx;
- if (sticky&STICK_NORTH && sticky&STICK_SOUTH)
- *height += diffy;
- if (!(sticky&STICK_WEST)) {
- if (sticky&STICK_EAST)
- *x += diffx;
- else
- *x += diffx/2;
- }
- if (!(sticky&STICK_NORTH)) {
- if (sticky&STICK_SOUTH)
- *y += diffy;
- else
- *y += diffy/2;
- }
- }
-
- /*
- * Figure out the minimum size (not counting the X border) of the
- * master based on the information from GetLayoutInfo()
- */
-
- static void
- GetMinSize(masterPtr, info, minw, minh)
- GridBag *masterPtr;
- LayoutInfo *info;
- int *minw;
- int *minh;
- {
- int i, t;
- int intBWidth; /* Width of internal border in parent window,
- * if any. */
-
- intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
-
- t = 0;
- for(i = 0; i < info->width; i++)
- t += info->minWidth[i];
- *minw = t + 2*intBWidth;
-
- t = 0;
- for(i = 0; i < info->height; i++)
- t += info->minHeight[i];
- *minh = t + 2*intBWidth;
- }
-
- /*
- *--------------------------------------------------------------
- *
- * ArrangeGrid --
- *
- * This procedure is invoked (using the Tk_DoWhenIdle
- * mechanism) to re-layout a set of windows managed by
- * the gridbag. It is invoked at idle time so that a
- * series of gridbag requests can be merged into a single
- * layout operation.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The slaves of masterPtr may get resized or moved.
- *
- *--------------------------------------------------------------
- */
-
- static void
- ArrangeGrid(clientData)
- ClientData clientData; /* Structure describing parent whose slaves
- * are to be re-layed out. */
- {
- register GridBag *masterPtr = (GridBag *) clientData;
- register GridBag *slavePtr;
- int abort;
- int i, x, y, width, height;
- int diffw, diffh;
- double weight;
- Tk_Window parent, ancestor;
- LayoutInfo info;
- int intBWidth; /* Width of internal border in parent window,
- * if any. */
- int iPadX, iPadY;
-
- masterPtr->flags &= ~REQUESTED_RELAYOUT;
-
- /*
- * If the parent has no slaves anymore, then don't do anything
- * at all: just leave the parent's size as-is.
- * Even if row and column constraints have been set!
- */
-
- if (masterPtr->slavePtr == NULL) {
- return;
- }
-
- /*
- * Abort any nested call to ArrangeGrid for this window, since
- * we'll do everything necessary here, and set up so this call
- * can be aborted if necessary.
- */
-
- if (masterPtr->abortPtr != NULL) {
- *masterPtr->abortPtr = 1;
- }
- masterPtr->abortPtr = &abort;
- abort = 0;
- Tk_Preserve((ClientData) masterPtr);
-
- /*
- * Pass #1: scan all the slaves to figure out the total amount
- * of space needed.
- */
-
- GetLayoutInfo(masterPtr, &info);
- GetMinSize(masterPtr, &info, &width, &height);
-
- if (((width != Tk_ReqWidth(masterPtr->tkwin))
- || (height != Tk_ReqHeight(masterPtr->tkwin)))
- && !(masterPtr->flags & DONT_PROPAGATE)) {
- Tk_GeometryRequest(masterPtr->tkwin, width, height);
- masterPtr->flags |= REQUESTED_RELAYOUT;
- masterPtr->valid = 0;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
- goto done;
- }
-
- /*
- * If the parent isn't mapped then don't do anything more: wait
- * until it gets mapped again. Need to get at least to here to
- * reflect size needs up the window hierarchy, but there's no
- * point in actually mapping the slaves.
- */
-
- if (!Tk_IsMapped(masterPtr->tkwin)) {
- goto done;
- }
-
-
- /*
- * If the current dimensions of the window don't match the desired
- * dimensions, then adjust the minWidth and minHeight arrays
- * according to the weights.
- */
-
- diffw = Tk_Width(masterPtr->tkwin) - (width + masterPtr->iPadX);
- if (diffw != 0) {
- weight = 0.0;
- for (i = 0; i < info.width; i++)
- weight += info.weightX[i];
- if (weight > MINWEIGHT) {
- for (i = 0; i < info.width; i++) {
- int dx = (int)(( ((double)diffw) * info.weightX[i]) / weight);
- info.minWidth[i] += dx;
- width += dx;
- if (info.minWidth[i] < 0) {
- width -= info.minWidth[i];
- info.minWidth[i] = 0;
- }
- }
- }
- diffw = Tk_Width(masterPtr->tkwin) - (width + masterPtr->iPadX);
- }
- else {
- diffw = 0;
- }
-
- diffh = Tk_Height(masterPtr->tkwin) - (height + masterPtr->iPadY);
- if (diffh != 0) {
- weight = 0.0;
- for (i = 0; i < info.height; i++)
- weight += info.weightY[i];
- if (weight > MINWEIGHT) {
- for (i = 0; i < info.height; i++) {
- int dy = (int)(( ((double)diffh) * info.weightY[i]) / weight);
- info.minHeight[i] += dy;
- height += dy;
- if (info.minHeight[i] < 0) {
- height -= info.minHeight[i];
- info.minHeight[i] = 0;
- }
- }
- }
- diffh = Tk_Height(masterPtr->tkwin) - (height + masterPtr->iPadY);
- }
- else {
- diffh = 0;
- }
-
- /*
- * Now do the actual layout of the slaves using the layout information
- * that has been collected.
- */
-
- iPadX = masterPtr->iPadX/2;
- iPadY = masterPtr->iPadY/2;
- intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
-
- for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
- slavePtr = slavePtr->nextPtr) {
-
- masterPtr->startx = x = diffw/2 + intBWidth + iPadX;
- for(i = 0; i < slavePtr->tempX; i++)
- x += info.minWidth[i];
-
- masterPtr->starty = y = diffh/2 + intBWidth + iPadY;
- for(i = 0; i < slavePtr->tempY; i++)
- y += info.minHeight[i];
-
- width = 0;
- for(i = slavePtr->tempX; i < (slavePtr->tempX + slavePtr->tempWidth); i++)
- width += info.minWidth[i];
-
- height = 0;
- for(i = slavePtr->tempY; i < (slavePtr->tempY + slavePtr->tempHeight); i++)
- height += info.minHeight[i];
-
- AdjustForGravity(slavePtr, &x, &y, &width, &height);
-
- /*
- * If the window in which slavePtr is managed is not its
- * parent in the window hierarchy, translate the coordinates
- * to the coordinate system of the real X parent.
- */
-
- parent = Tk_Parent(slavePtr->tkwin);
- for (ancestor = masterPtr->tkwin; ancestor != parent;
- ancestor = Tk_Parent(ancestor)) {
- x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
- y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
- }
-
- /*
- * If the window is too small to be interesting then
- * unmap it. Otherwise configure it and then make sure
- * it's mapped.
- */
-
- if ((width <= 0) || (height <= 0)) {
- Tk_UnmapWindow(slavePtr->tkwin);
- }
- else {
- if ((x != Tk_X(slavePtr->tkwin))
- || (y != Tk_Y(slavePtr->tkwin))
- || (width != Tk_Width(slavePtr->tkwin))
- || (height != Tk_Height(slavePtr->tkwin))) {
- Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
- }
- if (abort) {
- goto done;
- }
- Tk_MapWindow(slavePtr->tkwin);
- }
-
- /*
- * Changes to the window's structure could cause almost anything
- * to happen, including deleting the parent or child. If this
- * happens, we'll be told to abort.
- */
-
- if (abort) {
- goto done;
- }
- }
-
- done:
- masterPtr->abortPtr = NULL;
- Tk_Release((ClientData) masterPtr);
- }
-
-
-
- /*
- *--------------------------------------------------------------
- *
- * GetGridBag --
- *
- * This internal procedure is used to locate a GridBag
- * structure for a given window, creating one if one
- * doesn't exist already.
- *
- * Results:
- * The return value is a pointer to the GridBag structure
- * corresponding to tkwin.
- *
- * Side effects:
- * A new gridbag structure may be created. If so, then
- * a callback is set up to clean things up when the
- * window is deleted.
- *
- *--------------------------------------------------------------
- */
-
- static GridBag *
- GetGridBag(tkwin)
- Tk_Window tkwin; /* Token for window for which
- * gridbag structure is desired. */
- {
- register GridBag *gridPtr;
- Tcl_HashEntry *hPtr;
- int new;
-
- if (!initialized) {
- initialized = 1;
- Tcl_InitHashTable(&gridBagHashTable, TCL_ONE_WORD_KEYS);
- }
-
- /*
- * See if there's already gridbag for this window. If not,
- * then create a new one.
- */
-
- hPtr = Tcl_CreateHashEntry(&gridBagHashTable, (char *) tkwin, &new);
- if (!new) {
- return (GridBag *) Tcl_GetHashValue(hPtr);
- }
- gridPtr = (GridBag *) ckalloc(sizeof(GridBag));
- gridPtr->tkwin = tkwin;
- gridPtr->masterPtr = NULL;
- gridPtr->nextPtr = NULL;
- gridPtr->slavePtr = NULL;
-
- gridPtr->gridColumn = gridPtr->gridRow = -1;
- gridPtr->gridWidth = gridPtr->gridHeight = 1;
- gridPtr->weightX = gridPtr->weightY = 0.0;
- gridPtr->minWidth = gridPtr->minHeight = 0;
-
- gridPtr->padX = gridPtr->padY = 0;
- gridPtr->iPadX = gridPtr->iPadY = 0;
- gridPtr->startx = gridPtr->starty = 0;
- gridPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
- gridPtr->abortPtr = NULL;
- gridPtr->flags = 0;
-
- gridPtr->column.max = 0;
- gridPtr->row.max = 0;
- gridPtr->column.used = 0;
- gridPtr->row.used = 0;
-
- gridPtr->valid = 0;
- gridPtr->layoutCache = NULL;
-
- Tcl_SetHashValue(hPtr, gridPtr);
- Tk_CreateEventHandler(tkwin, StructureNotifyMask,
- GridBagStructureProc, (ClientData) gridPtr);
- return gridPtr;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Unlink --
- *
- * Remove a gridbag from its parent's list of slaves.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The parent will be scheduled for re-arranging.
- *
- *----------------------------------------------------------------------
- */
-
- static void
- Unlink(gridPtr)
- register GridBag *gridPtr; /* Window to unlink. */
- {
- register GridBag *masterPtr, *gridPtr2;
-
- masterPtr = gridPtr->masterPtr;
- if (masterPtr == NULL) {
- return;
- }
- if (masterPtr->slavePtr == gridPtr) {
- masterPtr->slavePtr = gridPtr->nextPtr;
- }
- else {
- for (gridPtr2 = masterPtr->slavePtr; ; gridPtr2 = gridPtr2->nextPtr) {
- if (gridPtr2 == NULL) {
- panic("Unlink couldn't find previous window");
- }
- if (gridPtr2->nextPtr == gridPtr) {
- gridPtr2->nextPtr = gridPtr->nextPtr;
- break;
- }
- }
- }
- masterPtr->valid = 0;
- if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
- masterPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
- }
- if (masterPtr->abortPtr != NULL) {
- *masterPtr->abortPtr = 1;
- }
-
- gridPtr->masterPtr = NULL;
- }
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * DestroyGridBag --
- *
- * This procedure is invoked by Tk_EventuallyFree or Tk_Release
- * to clean up the internal structure of a gridbag at a safe time
- * (when no-one is using it anymore).
- *
- * Results:
- * None.
- *
- * Side effects:
- * Everything associated with the gridbag is freed up.
- *
- *----------------------------------------------------------------------
- */
-
- static void
- DestroyGridBag(memPtr)
- char *memPtr; /* Info about window that is now dead. */
- {
- register GridBag *gridPtr = (GridBag *) memPtr;
-
- if (gridPtr->column.max) {
- ckfree((char *) gridPtr->column.minsize);
- ckfree((char *) gridPtr->column.weight);
- }
- if (gridPtr->row.max) {
- ckfree((char *) gridPtr->row.minsize);
- ckfree((char *) gridPtr->row.weight);
- }
- if (gridPtr->layoutCache)
- ckfree((char *) gridPtr->layoutCache);
-
- ckfree((char *) gridPtr);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * GridBagStructureProc --
- *
- * This procedure is invoked by the Tk event dispatcher in response
- * to StructureNotify events.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If a window was just deleted, clean up all its gridbag-related
- * information. If it was just resized, re-configure its slaves, if
- * any.
- *
- *----------------------------------------------------------------------
- */
-
- static void
- GridBagStructureProc(clientData, eventPtr)
- ClientData clientData; /* Our information about window
- * referred to by eventPtr. */
- XEvent *eventPtr; /* Describes what just happened. */
- {
- register GridBag *gridPtr = (GridBag *) clientData;
-
- if (eventPtr->type == ConfigureNotify) {
- gridPtr->valid = 0;
- if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
- gridPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
- }
- if (gridPtr->doubleBw != 2*Tk_Changes(gridPtr->tkwin)->border_width) {
- if ((gridPtr->masterPtr != NULL) &&
- !(gridPtr->masterPtr->flags & REQUESTED_RELAYOUT)) {
- gridPtr->doubleBw = 2*Tk_Changes(gridPtr->tkwin)->border_width;
- gridPtr->masterPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr->masterPtr);
- }
- }
- }
- else if (eventPtr->type == DestroyNotify) {
- register GridBag *gridPtr2, *nextPtr;
-
- if (gridPtr->masterPtr != NULL) {
- Unlink(gridPtr);
- }
- for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
- gridPtr2 = nextPtr) {
- Tk_UnmapWindow(gridPtr2->tkwin);
- gridPtr2->masterPtr = NULL;
- nextPtr = gridPtr2->nextPtr;
- gridPtr2->nextPtr = NULL;
- }
- Tcl_DeleteHashEntry(Tcl_FindHashEntry(&gridBagHashTable,
- (char *) gridPtr->tkwin));
- if (gridPtr->flags & REQUESTED_RELAYOUT) {
- Tk_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr);
- }
- gridPtr->tkwin = NULL;
- Tk_EventuallyFree((ClientData) gridPtr, DestroyGridBag);
- }
- else if (eventPtr->type == MapNotify) {
- gridPtr->valid = 0;
- if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
- gridPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
- }
- }
- else if (eventPtr->type == UnmapNotify) {
- register GridBag *gridPtr2;
-
- for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
- gridPtr2 = gridPtr2->nextPtr) {
- Tk_UnmapWindow(gridPtr2->tkwin);
- }
- }
- }
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * ConfigureSlaves --
- *
- * This implements the guts of the "grid configure" command. Given
- * a list of slaves and configuration options, it arranges for the
- * gridbag to manage the slaves and sets the specified options.
- *
- * Results:
- * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is
- * returned and interp->result is set to contain an error message.
- *
- * Side effects:
- * Slave windows get taken over by the gridbag.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- ConfigureSlaves(interp, tkwin, argc, argv)
- Tcl_Interp *interp; /* Interpreter for error reporting. */
- Tk_Window tkwin; /* Any window in application containing
- * slaves. Used to look up slave names. */
- int argc; /* Numb = 0er of elements in argv. */
- char *argv[]; /* Argument strings: contains one or more
- * window names followed by any number
- * of "option value" pairs. Caller must
- * make sure that there is at least one
- * window name. */
- {
- GridBag *masterPtr, *slavePtr, *prevPtr;
- Tk_Window other, slave, parent, ancestor;
- int i, j, numWindows, c, length, tmp, positionGiven;
- int currentColumn=0, numColumns=1;
- int gotLayout = 0;
- int gotWidth = 0;
- int width;
-
- /*
- * Find out how many windows are specified. (shouldn't use harwired symbols)
- */
-
- for (numWindows = 0; numWindows < argc; numWindows++) {
- if (argv[numWindows][0] != '.'
- && strcmp(argv[numWindows],"-")!=0
- && strcmp(argv[numWindows],"^")!=0
- && strcmp(argv[numWindows],"x")!=0) {
- break;
- }
- }
- slave = NULL;
-
- /*
- * Iterate over all of the slave windows, parsing the configuration
- * options for each slave. It's a bit wasteful to re-parse the
- * options for each slave, but things get too messy if we try to
- * parse the arguments just once at the beginning. For example,
- * if a slave already is managed we want to just change a few
- * existing values without resetting everything. If there are
- * multiple windows, the -in option only gets processed for the
- * first window.
- */
-
- masterPtr = NULL;
- prevPtr = NULL;
- positionGiven = 0;
- for (j = 0; j < numWindows; j++) {
-
- /* adjust default widget location for non-widgets */
- if (*argv[j] != '.') {
- switch (*argv[j]) {
- case '^': /* extend the widget in the previous row
- * Since we don't know who the master is yet,
- * handle these in a separate pass at the end
- */
- /* no break */
- case REL_SKIP: /* skip over the next column */
- currentColumn++;
- break;
- case REL_HORIZ: /* increase the span, already dealt with */
- /* not quite right */
- if (j>0 && (*argv[j-1] == REL_SKIP || *argv[j-1] == '^')) {
- Tcl_AppendResult(interp, "Invalid grid combination:",
- " \"-\" can't follow \"", argv[j-1], "\"",NULL);
- return TCL_ERROR;
- }
- break;
- default:
- panic("Invalid grid position indicator");
- }
- continue;
- }
-
- for (numColumns=1; j+numColumns < numWindows && *argv[j+numColumns] == REL_HORIZ;
- numColumns++) {
- /* null body */
- }
- slave = Tk_NameToWindow(interp, argv[j], tkwin);
- if (slave == NULL) {
- return TCL_ERROR;
- }
- if (Tk_IsTopLevel(slave)) {
- Tcl_AppendResult(interp, "can't manage \"", argv[j],
- "\": it's a top-level window", (char *) NULL);
- return TCL_ERROR;
- }
- slavePtr = GetGridBag(slave);
-
- /*
- * The following statement is taken from tkPack.c:
- *
- * "If the slave isn't currently managed, reset all of its
- * configuration information to default values (there could
- * be old values left from a previous packer)."
- *
- * I disagree with this statement. If a slave is disabled (using
- * "forget") and then re-enabled, I submit that 90% of the time the
- * programmer will want it to retain its old configuration information.
- * If the programmer doesn't want this behavior, then she can reset the
- * defaults for herself, but she will never have to worry about keeping
- * track of the old state.
- */
-
- for (i = numWindows; i < argc; i+=2) {
- if ((i+2) > argc) {
- Tcl_AppendResult(interp, "extra option \"", argv[i],
- "\" (option with no value?)", (char *) NULL);
- return TCL_ERROR;
- }
- length = strlen(argv[i]);
- if (length < 2) {
- goto badOption;
- }
- c = argv[i][1];
- if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) {
- if (j == 0) {
- other = Tk_NameToWindow(interp, argv[i+1], tkwin);
- if (other == NULL) {
- return TCL_ERROR;
- }
- if (other == slave) {
- sprintf(interp->result,"Window can't be managed in itself");
- return TCL_ERROR;
- }
- masterPtr = GetGridBag(other);
- prevPtr = masterPtr->slavePtr;
- if (prevPtr != NULL) {
- while (prevPtr->nextPtr != NULL) {
- prevPtr = prevPtr->nextPtr;
- }
- }
- positionGiven = 1;
- }
- } else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) {
- if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
- || (tmp < 0)) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad ipadx value \"", argv[i+1],
- "\": must be positive screen distance",
- (char *) NULL);
- return TCL_ERROR;
- }
- slavePtr->iPadX = tmp*2;
- } else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) {
- if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
- || (tmp< 0)) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad ipady value \"", argv[i+1],
- "\": must be positive screen distance",
- (char *) NULL);
- return TCL_ERROR;
- }
- slavePtr->iPadY = tmp*2;
- } else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) {
- if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
- || (tmp< 0)) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad padx value \"", argv[i+1],
- "\": must be positive screen distance",
- (char *) NULL);
- return TCL_ERROR;
- }
- slavePtr->padX = tmp*2;
- } else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) {
- if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
- || (tmp< 0)) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad pady value \"", argv[i+1],
- "\": must be positive screen distance",
- (char *) NULL);
- return TCL_ERROR;
- }
- slavePtr->padY = tmp*2;
- } else if ((c == 'c') && (strcmp(argv[i], "-column") == 0)) {
- if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad column value \"", argv[i+1],
- "\": must be a non-negative integer", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->gridColumn = tmp;
- } else if ((c == 'r') && (strcmp(argv[i], "-row") == 0)) {
- if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad grid value \"", argv[i+1],
- "\": must be a non-negative integer", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->gridRow = tmp;
- } else if ((c == 'c') && (strcmp(argv[i], "-columnspan") == 0)) {
- if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp <= 0) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad columnspan value \"", argv[i+1],
- "\": must be a positive integer", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->gridWidth = tmp;
- gotWidth++;
- } else if ((c == 'r') && (strcmp(argv[i], "-rowspan") == 0)) {
- if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad rowspan value \"", argv[i+1],
- "\": must be a positive integer", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->gridHeight = tmp;
- /*
- } else if ((c == 'w') &&
- (!strcmp(argv[i], "-weightx") || !strcmp(argv[i], "-wx"))) {
- if (Tcl_GetDouble(interp, argv[i+1], &tmp_dbl) != TCL_OK) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad weight value \"", argv[i+1],
- "\": must be a double", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->weightX = tmp_dbl;
- }
- else if ((c == 'w') &&
- (!strcmp(argv[i], "-weighty") || !strcmp(argv[i], "-wy"))) {
- if (Tcl_GetDouble(interp, argv[i+1], &tmp_dbl) != TCL_OK) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "bad weight value \"", argv[i+1],
- "\": must be a double", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->weightY = tmp_dbl;
- */
- } else if ((c == 's') && strcmp(argv[i], "-sticky") == 0) {
- int sticky = StringToSticky(argv[i+1]);
- if (sticky == -1) {
- Tcl_AppendResult(interp, "bad stickyness value \"", argv[i+1],
- "\": must be a string containing n, e, s, and/or w", (char *)NULL);
- return TCL_ERROR;
- }
- slavePtr->flags = sticky | (slavePtr->flags & ~STICK_ALL);
- } else {
- badOption:
- Tcl_AppendResult(interp, "unknown or ambiguous option \"",
- argv[i], "\": must be -in, -sticky, ",
- "-row, -column, -rowspan, -columnspan, ",
- "-ipadx, -ipady, -padx or -pady.",
- (char *) NULL);
- return TCL_ERROR;
- }
- }
-
- /*
- * If no position in a gridbag list was specified and the slave
- * is already managed, then leave it in its current location in
- * its current gridbag list.
- */
-
- if (!positionGiven && (slavePtr->masterPtr != NULL)) {
- masterPtr = slavePtr->masterPtr;
- goto scheduleLayout;
- }
-
- /*
- * If the slave is going to be put back after itself then
- * skip the whole operation, since it won't work anyway.
- */
-
- if (prevPtr == slavePtr) {
- masterPtr = slavePtr->masterPtr;
- goto scheduleLayout;
- }
-
- /*
- * If the "-in" option has not been specified, arrange for the
- * slave to go at the end of the order for its parent.
- */
-
- if (!positionGiven) {
- masterPtr = GetGridBag(Tk_Parent(slave));
- prevPtr = masterPtr->slavePtr;
- if (prevPtr != NULL) {
- while (prevPtr->nextPtr != NULL) {
- prevPtr = prevPtr->nextPtr;
- }
- }
- }
-
- /*
- * Make sure that the slave's parent is either the master or
- * an ancestor of the master.
- */
-
- parent = Tk_Parent(slave);
- for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
- if (ancestor == parent) {
- break;
- }
- if (Tk_IsTopLevel(ancestor)) {
- Tcl_AppendResult(interp, "can't put ", argv[j],
- " inside ", Tk_PathName(masterPtr->tkwin),
- (char *) NULL);
- return TCL_ERROR;
- }
- }
-
- /*
- * Unlink the slave if it's currently managed, then position it
- * after prevPtr.
- */
-
- if (slavePtr->masterPtr != NULL) {
- Unlink(slavePtr);
- }
- slavePtr->masterPtr = masterPtr;
- if (prevPtr == NULL) {
- slavePtr->nextPtr = masterPtr->slavePtr;
- masterPtr->slavePtr = slavePtr;
- } else {
- slavePtr->nextPtr = prevPtr->nextPtr;
- prevPtr->nextPtr = slavePtr;
- }
- Tk_ManageGeometry(slave, &gridMgrType, (ClientData) slavePtr);
- prevPtr = slavePtr;
-
- /* assign default row and column */
-
- if (slavePtr->gridColumn == -1) {
- slavePtr->gridColumn = currentColumn;
- }
- slavePtr->gridWidth += numColumns - 1;
- if (slavePtr->gridRow == -1) {
- if (!gotLayout++) GetCachedLayoutInfo(masterPtr);
- slavePtr->gridRow = masterPtr->layoutCache->lastRow;
- }
-
- /*
- * Arrange for the parent to be re-arranged at the first
- * idle moment.
- */
-
- scheduleLayout:
- if (masterPtr->abortPtr != NULL) {
- *masterPtr->abortPtr = 1;
- }
- masterPtr->valid = 0;
- if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
- masterPtr->flags |= REQUESTED_RELAYOUT;
- Tk_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
- }
- currentColumn += slavePtr->gridWidth;
- numColumns = 1;
- }
-
- /* now look for all the "^"'s */
-
- for (j = 0; j < numWindows; j++) {
- struct GridBag *otherPtr;
- char *lastWindow; /* use this window to base current row/col on */
- int match; /* found a match for the ^ */
-
- if (*argv[j] == '.') {
- lastWindow = argv[j];
- }
- if (*argv[j] != '^') {
- continue;
- }
- for (width=1; width+j < numWindows && *argv[j+width] == '^'; width++) {
- /* Null Body */
- }
- other = Tk_NameToWindow(interp, lastWindow, tkwin);
- otherPtr = GetGridBag(other);
- if (!gotLayout++) GetCachedLayoutInfo(masterPtr);
-
- for (match=0, slavePtr = masterPtr->slavePtr; slavePtr != NULL;
- slavePtr = slavePtr->nextPtr) {
-
- if (slavePtr->gridWidth == width
- && slavePtr->gridColumn == otherPtr->gridColumn + otherPtr->gridWidth
- && slavePtr->gridRow + slavePtr->gridHeight == otherPtr->gridRow) {
- slavePtr->gridHeight++;
- match++;
- }
- lastWindow = Tk_PathName(slavePtr->tkwin);
- }
- if (!match) {
- Tcl_AppendResult(interp, "can't find slave to extend with \"^\"",
- " after ",lastWindow,
- (char *) NULL);
- return TCL_ERROR;
- }
- j += width - 1;
- }
- return TCL_OK;
- }
-
- /* convert "Sticky" bits into a string */
-
- static void
- StickyToString(flags, result)
- int flags; /* the sticky flags */
- char *result; /* where to put the result */
- {
- int count = 0;
- if (flags&STICK_NORTH) result[count++] = 'n';
- if (flags&STICK_EAST) result[count++] = 'e';
- if (flags&STICK_SOUTH) result[count++] = 's';
- if (flags&STICK_WEST) result[count++] = 'w';
- if (count) {
- result[count] = '\0';
- } else {
- sprintf(result,"{}");
- }
- }
-
- /* convert sticky string to flags */
-
- static int
- StringToSticky(string)
- char *string;
- {
- int sticky = 0;
- char c;
-
- while ((c = *string++) != '\0') {
- switch (c) {
- case 'n': case 'N': sticky |= STICK_NORTH; break;
- case 'e': case 'E': sticky |= STICK_EAST; break;
- case 's': case 'S': sticky |= STICK_SOUTH; break;
- case 'w': case 'W': sticky |= STICK_WEST; break;
- case ' ': case ',': case '\t': case '\r': case '\n': break;
- default: return -1;
- }
- }
- return sticky;
- }
-